/**
 * Copyright (c) 2007, Blue Hole Software. All rights reserved.
 * Code licensed under the Apache 2.0 License:
 * http://www.apache.org/licenses/
 */
package org.bhf.security.common;

import javax.security.auth.Subject;
import java.io.Serializable;
import java.security.Principal;
import java.util.Set;

/**
 * Public credential that uniquely identifies the user. Each authenticated
 * <code>Subject</code> carries a <code>UserID</code> as a public
 * credential. The ID may be used to uniquely identify the user or to
 * retrieve additional information about the user through the available
 * mechanisms.
 */
public final class UserID implements Principal, Serializable
{
    private static final long           serialVersionUID    = 7930732926638008763L;
    private static final Class<UserID>  THIS_CLASS          = UserID.class;

    /** Role name */
    private final String ID;

    /**
     * Create a <code>UserID</code> with the given ID.
     *
     * @param ID the ID. Must not be <code>null</code>.
     *
     * @throws java.lang.IllegalArgumentException if <code>ID == null</code>.
     */
    public UserID( final String ID )
    {
        if( ID == null )
            throw new IllegalArgumentException( "ID == null" );

        this.ID = ID;
    }

    /**
     * Returns the ID of this <code>UserID</code>.
     * @return the ID of this <code>UserID</code>.
     */
    public String           getID()
    {
        return ID;
    }

    /**
     * Returns the name (actuall the ID) of this <code>Principal</code>.
     * @return the name of this <code>Principal</code>.
     */
    public String           getName()
    {
        return ID;
    }

    /**
     * Convenience method to return the <code>UserID</code> in a
     * <code>Subject</code>.
     *
     * @return The <code>UserID</code> of the given <code>Subject</code>
     *
     * @param subject The <code>Subject</code> from which to extract the
     *      <code>UserID</code>.  Must not be <code>null</code>.
     *
     * @throws java.lang.IllegalArgumentException if <code>subject == null</code>
     *      or if <code>subject</code> does not contain exactly one
     *      <code>UserID</code> as a public credential.
     */
    public static UserID    getUserID( final Subject subject )
    {
        if( subject == null )
            throw new IllegalArgumentException( "subject == null" );

        final Set<UserID> set = subject.getPrincipals( THIS_CLASS );

        if( set.size() != 1 )
            throw new IllegalArgumentException( "subject.getPrincipals( UserID.class ).size() != 1" );

        return set.iterator().next();
    }

    /**
     * Convenience method to return the <code>UserID</code> of the
     * <code>Subject</code> associated with the current thread.
     *
     * @return The <code>UserID</code> of the contextual <code>Subject</code>
     *
     * @throws java.lang.IllegalArgumentException if <code>subject</code> does not
     *      contain exactly one <code>UserID</code> as a public credential
     *      or if there is no code>Subject</code> associated with the
     *      current thread.
     */
    public static UserID    getUserID()
    {
        return getUserID( ContextSubject.getContextSubject() );
    }

    /**
     * The hash code based on ID.
     *
     * @return the hash code.
     */
    public int              hashCode()
    {
        return ID.hashCode();
    }

    /**
     * Equality based on ID.
     *
     * @param o Object against which to compare
     *
     * @return <code>true</code> iff <code>o</code> is a <code>UserID</code>
     *      with the same ID.
     */
    public boolean          equals( final Object o )
    {
        try
        {
            return ((UserID)o).ID.equals( ID );
        }
        catch( Exception e )
        {
            return false;
        }
    }
}


